package com.gitee.wsl.doc.prosemirror.state.command

import com.gitee.wsl.doc.prosemirror.model.content.ContentMatch
import com.gitee.wsl.doc.prosemirror.model.node.NodeType
import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.state.CommandDispatch
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.selection.Selection
import com.gitee.wsl.doc.prosemirror.transform.ext.replaceWith

object ExitCode : Command{
    override fun exec(
        state: EditorState,
        dispatch: CommandDispatch?,
    ): Boolean {
        val head = state.selection._head
        val anchor = state.selection._anchor

        // 检查父节点是否为代码类型且选择在同一父节点内
        if (!head.parent.type.spec.code || !head.sameParent(anchor)) {
            return false
        }

        val above = head.node(-1)
        val after = head.indexAfter(-1)
        val type = defaultBlockAt(above.contentMatchAt(after))

        // 检查是否可以创建新块
        if (type == null || !above.canReplaceWith(after, after, type)) {
            return false
        }

        if (dispatch != null) {
            val pos = head.after()
            val tr = state.tr.replaceWith(pos, pos, type.createAndFill()!!)
            tr.setSelection(Selection.near(tr.doc.resolve(pos), 1))
            dispatch(tr.scrollIntoView())
        }

        return true
    }
}

/**
 * 当选择位于具有 truthy `code` 属性的节点中时，在代码块后创建默认块并移动光标
 * @param state 编辑器状态
 * @param dispatch 事务处理回调函数
 * @return 操作是否成功执行
 */
val Command.Companion.exitCode get() = ExitCode

fun defaultBlockAt(match: ContentMatch): NodeType? {
    (0..match.edgeCount).forEach {
        val type = match.edge(it).type
        if (type.isTextblock && !type.hasRequiredAttrs())
            return type
    }
    return null
}